package com.youlai.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.constant.SystemConstants;
import com.youlai.system.common.model.Option;
import com.youlai.system.common.util.DateUtils;
import com.youlai.system.converter.UserConverter;
import com.youlai.system.model.entity.SysRole;
import com.youlai.system.model.vo.UserBusinessCard;
import com.youlai.system.security.util.SecurityUtils;
import com.youlai.system.mapper.SysUserMapper;
import com.youlai.system.model.dto.UserAuthInfo;
import com.youlai.system.model.bo.UserBO;
import com.youlai.system.model.bo.UserFormBO;
import com.youlai.system.model.entity.SysUser;
import com.youlai.system.model.form.UserForm;
import com.youlai.system.model.query.UserPageQuery;
import com.youlai.system.model.vo.UserExportVO;
import com.youlai.system.model.vo.UserInfoVO;
import com.youlai.system.model.vo.UserPageVO;
import com.youlai.system.security.service.PermissionService;
import com.youlai.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户业务实现类
 *
 * @author haoxr
 * @since 2022/1/14
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private final PasswordEncoder passwordEncoder;

    private final SysUserRoleService userRoleService;

    private final UserConverter userConverter;

    private final SysMenuService menuService;

    private final SysRoleService roleService;

    private final PermissionService permissionService;

    @Override
    public Long saveStudent(String account, String name) {
        SysUser user = new SysUser();
        user.setUsername(account);
        user.setNickname(name);
        // 设置默认加密密码
        String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
        user.setPassword(defaultEncryptPwd);
        save(user);
        return user.getId();
    }

    @Override
    public SysUser saveStudent(String account, String name, Long sourceId, Long positionId, Long gradeId) {
        SysUser user = new SysUser();
        user.setUsername(account);
        user.setNickname(name);
        user.setSourceId(sourceId);
        user.setPositionId(positionId);
        user.setGradeId(gradeId);
        // 设置默认加密密码
        String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
        user.setPassword(defaultEncryptPwd);
        save(user);
        return user;
    }

    @Override
    public SysUser saveTeacher(String account, String name, Long deptId) {
        SysUser user = new SysUser();
        user.setUsername(account);
        user.setNickname(name);
        user.setDeptId(deptId);
        // 设置默认加密密码
        String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
        user.setPassword(defaultEncryptPwd);
        save(user);
        return user;
    }

    @Override
    public SysUser getByAccountAndName(String account, String name) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, account).eq(SysUser::getNickname, name);
        return getOne(queryWrapper);
    }

    @Override
    public SysUser getByAccount(String account) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, account);
        return getOne(queryWrapper);
    }

    /**
     * 获取用户分页列表
     *
     * @param queryParams
     * @return
     */
    @Override
    public IPage<UserPageVO> getUserPage(UserPageQuery queryParams) {

        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<UserBO> page = new Page<>(pageNum, pageSize);

        // 格式化为数据库日期格式，避免日期比较使用格式化函数导致索引失效
        DateUtils.toDatabaseFormat(queryParams, "startTime", "endTime");

        // 查询数据
        Page<UserBO> userPage = this.baseMapper.getUserPage(page, queryParams);

        // 实体转换
        return userConverter.toPageVo(userPage);
    }

    /**
     * 获取用户详情
     *
     * @param userId
     * @return
     */
    @Override
    public UserForm getUserFormData(Long userId) {
        UserFormBO userFormBO = this.baseMapper.getUserDetail(userId);
        // 实体转换po->form
        UserForm userForm = userConverter.bo2Form(userFormBO);
        return userForm;
    }

    /**
     * 新增用户
     *
     * @param userForm 用户表单对象
     * @return
     */
    @Override
    public boolean saveUser(UserForm userForm) {

        String username = userForm.getUsername();

        long count = this.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
        Assert.isTrue(count == 0, "用户名已存在");

        // 实体转换 form->entity
        SysUser entity = userConverter.form2Entity(userForm);

        // 设置默认加密密码
        String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
        entity.setPassword(defaultEncryptPwd);

        // 新增用户
        boolean result = this.save(entity);

        if (result) {
            // 保存用户角色
            userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
        }
        return result;
    }

    /**
     * 更新用户
     *
     * @param userId   用户ID
     * @param userForm 用户表单对象
     * @return
     */
    @Override
    @Transactional
    public boolean updateUser(Long userId, UserForm userForm) {

        String username = userForm.getUsername();

        long count = this.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username).ne(SysUser::getId, userId));
        Assert.isTrue(count == 0, "用户名已存在");

        // form -> entity
        SysUser entity = userConverter.form2Entity(userForm);

        // 修改用户
        boolean result = this.updateById(entity);

        if (result) {
            // 保存用户角色
            userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
        }
        return result;
    }

    /**
     * 删除用户
     *
     * @param idsStr 用户ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteUsers(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的用户数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).collect(Collectors.toList());
        return this.removeByIds(ids);

    }

    /**
     * 修改用户密码
     *
     * @param userId   用户ID
     * @param password 用户密码
     * @return true|false
     */
    @Override
    public boolean updatePassword(Long userId, String password) {
        return this.update(new LambdaUpdateWrapper<SysUser>().eq(SysUser::getId, userId).set(SysUser::getPassword, passwordEncoder.encode(password)));
    }

    /**
     * 根据用户名获取认证信息
     *
     * @param username 用户名
     * @return 用户认证信息 {@link UserAuthInfo}
     */
    @Override
    public UserAuthInfo getUserAuthInfo(String username) {
        UserAuthInfo userAuthInfo = this.baseMapper.getUserAuthInfo(username);
        if (userAuthInfo != null) {
            Set<String> roles = userAuthInfo.getRoles();
            if (CollectionUtil.isNotEmpty(roles)) {
                Set<String> perms = menuService.listRolePerms(roles);
                userAuthInfo.setPerms(perms);
            }

            // 获取最大范围的数据权限
            Integer dataScope = roleService.getMaximumDataScope(roles);
            userAuthInfo.setDataScope(dataScope);
        }
        return userAuthInfo;
    }


    /**
     * 获取导出用户列表
     *
     * @param queryParams
     * @return
     */
    @Override
    public List<UserExportVO> listExportUsers(UserPageQuery queryParams) {
        List<UserExportVO> list = this.baseMapper.listExportUsers(queryParams);
        return list;
    }

    /**
     * 获取登录用户信息
     *
     * @return {@link UserInfoVO}   用户信息
     */
    @Override
    public UserInfoVO getCurrentUserInfo() {

        String username = SecurityUtils.getUser().getUsername(); // 登录用户名

        // 获取登录用户基础信息
        SysUser user = this.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username).select(SysUser::getId, SysUser::getUsername, SysUser::getNickname, SysUser::getAvatar));
        // entity->VO
        UserInfoVO userInfoVO = userConverter.toUserInfoVo(user);

        // 用户角色集合
        Set<String> roles = SecurityUtils.getRoles();
        userInfoVO.setRoles(roles);

        // 用户权限集合
        if (CollectionUtil.isNotEmpty(roles)) {
            Set<String> perms = permissionService.getRolePermsFormCache(roles);
            userInfoVO.setPerms(perms);
        }
        return userInfoVO;
    }

    @Override
    public List<SysUser> getDeptUserCountList() {
        QueryWrapper<SysUser> queryWrapper = Wrappers.query();
        queryWrapper.select("dept_id", "count(*) as count").isNotNull("dept_id").groupBy("dept_id");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<SysUser> getDeptUserCountList2() {
        QueryWrapper<SysUser> queryWrapper = Wrappers.query();
        queryWrapper.select("dept_id", "count(*) as count", "GROUP_CONCAT(nickname) as groupNickName")
                .isNotNull("dept_id").groupBy("dept_id");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Map<Long, Integer> deptUserCountMap() {
        return getDeptUserCountList().stream().collect(Collectors.toMap(SysUser::getDeptId, SysUser::getCount));
    }

    @Override
    public Map<Long, SysUser> deptUserCountMap2() {
        return getDeptUserCountList2().stream().collect(Collectors.toMap(SysUser::getDeptId, it -> it));
    }

    @Override
    public List<SysUser> getSourceUserCountList() {
        QueryWrapper<SysUser> queryWrapper = Wrappers.query();
        queryWrapper.select("source_id", "count(*) as count", "GROUP_CONCAT(nickname) as groupNickName").isNotNull("source_id").groupBy("source_id");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Map<Long, SysUser> sourceUserCountMap() {
        return getSourceUserCountList().stream().collect(Collectors.toMap(SysUser::getSourceId, it -> it));
    }

    @Override
    public List<SysUser> getPositionUserCountList() {
        QueryWrapper<SysUser> queryWrapper = Wrappers.query();
        queryWrapper.select("position_id", "count(*) as count", "GROUP_CONCAT(nickname) as groupNickName")
                .isNotNull("position_id").groupBy("position_id");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Map<Long, SysUser> positionUserCountMap() {
        return getPositionUserCountList().stream().collect(Collectors.toMap(SysUser::getPositionId, it -> it));
    }

    @Override
    public SysUser getBy(Long deptId, String nickName) {
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysUser::getDeptId, deptId).eq(SysUser::getNickname, nickName);
        return getOne(queryWrapper);
    }

    @Override
    public SysUser getBy(List<Long> userIdList, String nickName) {
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(SysUser::getId, userIdList).eq(SysUser::getNickname, nickName);
        return getOne(queryWrapper);
    }

    @Override
    public List<Option> listTeacherOptions() {
        SysRole role = roleService.getTeacherRole();
        List<Long> userIdList = userRoleService.getUserIdBy(role.getId());
        // 查询数据
        List<SysUser> categoryList = this.list(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getNickname).in(SysUser::getId, userIdList)
                .orderByAsc(SysUser::getUsername)
        );

        // 实体转换
        return userConverter.entities2Options(categoryList);
    }

    @Override
    public boolean sourceHasUsed(List<Long> sourceIdList) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUser::getSourceId, sourceIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean positionHasUsed(List<Long> positionIdList) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUser::getPositionId, positionIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean deptHasUsed(List<Long> deptIdList) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUser::getDeptId, deptIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public List<Long> idList() {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysUser::getId);
        return list(queryWrapper).stream().map(SysUser::getId).collect(Collectors.toList());
    }

    @Override
    public List<Long> idListByDeptId(Long deptId) {
        return this.baseMapper.idListByDeptId(deptId);
    }

    @Override
    public boolean updateAvatar(Long userId, String avatar) {
        return this.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, userId)
                .set(SysUser::getAvatar, avatar)
        );
    }

    @Override
    public UserBusinessCard getUserBusinessCard(Long userId) {
        return this.baseMapper.getUserBusinessCard(userId);
    }

    @Override
    public List<SysUser> getGradeUserCountList() {
        QueryWrapper<SysUser> queryWrapper = Wrappers.query();
        queryWrapper.select("grade_id", "count(*) as count", "GROUP_CONCAT(nickname) as groupNickName")
                .isNotNull("grade_id").groupBy("grade_id");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Map<Long, SysUser> gradeUserCountMap() {
        return getGradeUserCountList().stream().collect(Collectors.toMap(SysUser::getGradeId, it -> it));
    }

    @Override
    public boolean gradeHasUsed(List<Long> gradeIdList) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUser::getGradeId, gradeIdList);
        return count(queryWrapper) > 0;
    }


}
